import base64
import os
import uuid

from fastapi import FastAPI, HTTPException, Depends, File, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from starlette.concurrency import iterate_in_threadpool
from starlette.requests import Request
from starlette.responses import JSONResponse, HTMLResponse, Response
import Config.httpconfig as config
from Common.email import send_code
from Database import crud, schema
from Database.database import SessionLocal

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=[config.allowOrigins],
    allow_credentials=True,
    allow_methods=config.allowMethods,
    allow_headers=config.allowHeaders
)
templates = Jinja2Templates(directory="./Template")

logs = []

vertify = '123456'


@app.middleware("http")
async def options_middleware(request, call_next):
    if request.method == "OPTIONS":
        # 返回允许的 HTTP 方法和其他相关头部信息
        headers = {
            "Access-Control-Allow-Origin": str(config.allowOrigins),
            "Access-Control-Allow-Methods": ",".join(config.allowMethods),
            "Access-Control-Allow-Headers": str(config.allowHeaders),
            "Access-Control-Max-Age": "1728000"
        }
        return JSONResponse(content=None, status_code=200, headers=headers)
    else:
        response = await call_next(request)
        return response


# redis版本
# @app.middleware("http")
# async def log_request(request: Request, call_next):
#     request_name = str(uuid.uuid4())
#     # 记录请求的细节
#     add_set(request_name, f'Request: {request.method} {request.url.path}')
#     # 记录请求的原始内容
#     request_body = await request.body()
#     add_set(request_name, f'Request body: {request_body.decode()}')
#
#     response = await call_next(request)
#
#     # 记录响应的细节
#     add_set(request_name, f'Response: {response.status_code}')
#     # 记录响应的原始内容
#     response_body = await response.body()
#     add_set(request_name, f'Response body: {response_body.decode()}')
#
#     return response


@app.middleware("http")
async def log_request(request: Request, call_next):
    # 记录请求的细节
    request_log = {'url': f'Request: {request.method} {request.url.path}'}
    # 记录请求的原始内容
    request_body = await request.body()
    request_log['body'] = f'Request body: {request_body.decode()}'

    response = await call_next(request)

    # 记录响应的细节
    request_log['response_code'] = f'Response: {response.status_code}'
    # 记录响应的原始内容
    response_body = [chunk async for chunk in response.body_iterator]
    response.body_iterator = iterate_in_threadpool(iter(response_body))
    request_log['response_body'] = f"response_body={(b''.join(response_body)).decode()}"
    logs.append(request_log)
    return response


def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


@app.post('/posts')
async def post_upload(post: schema.PostBase, db: Session = Depends(get_db)):
    db_post = crud.add_post(db=db, post=post)
    return db_post


@app.post('/posts/detail/{postid}')
async def post_update(postid: int, post: schema.PostBase, db: Session = Depends(get_db)):
    try:
        crud.update_post(db=db, post=post, postid=postid)
    except Exception as e:
        return JSONResponse(content=e.__traceback__, status_code=400)
    else:
        return JSONResponse("更新成功")


@app.get('/posts/detail/{postid}/delete')
async def delete_post(postid: int, db: Session = Depends(get_db)):
    return crud.delete_post(db=db, postid=postid)


@app.get('/posts/user/{username}')
async def get_posts(username: str, db: Session = Depends(get_db)):
    result = crud.get_posts_by_username(db=db, username=username)
    print(result)
    return result


@app.post('/files/upload')
async def upload(files: list[UploadFile] = File()):
    filelist = []
    for f in files:
        file_content = await f.read()
        filename = './Files/' + str(uuid.uuid4()) + os.path.splitext(f.filename)[-1]
        with open(filename, "wb") as file:
            file.write(file_content)
            filelist.append(filename)
    result = ",".join(filelist)
    print(result)
    return JSONResponse(content=result, status_code=200)


@app.get('/users/{username}')
def get_user(username: str, db: Session = Depends(get_db)):
    db_user = crud.get_user_by_username(db, username=username)
    if not db_user:
        raise HTTPException(status_code=401, detail="找不到对应用户")
    user = {
        'username': db_user.username,
        'email': db_user.email,
        'role': db_user.role,
        'userid': db_user.userid
    }
    return JSONResponse(user)


@app.post('/users/login')
def login(user: schema.UserLogin, db: Session = Depends(get_db)):
    db_user = crud.user_check_password(db, username=user.username, password=user.password)
    if not db_user:
        raise HTTPException(status_code=401, detail="用户名或密码不正确")


@app.post('/users/register')
def register(user: schema.UserCreate, db: Session = Depends(get_db)):

    code = user.password[0:6]
    print(user.password, code)
    if code != vertify:
        raise HTTPException(status_code=401, detail='验证码不正确')
    user.password = user.password[6:]
    db_user = crud.get_user_by_email(db, email=user.email)

    if db_user:
        raise HTTPException(status_code=400, detail="邮箱已注册过")
    else:
        db_user = crud.get_user_by_username(db, username=user.username)
    if db_user:
        raise HTTPException(status_code=400, detail="用户名已被使用")
    return crud.create_user(db=db, inuser=user)


@app.get('/posts/review')
def get_unreviewed_posts(db: Session = Depends(get_db)):
    return crud.get_post_by_reviewed(db, 0)


@app.get('/posts/review')
def get_unreviewed_posts(db: Session = Depends(get_db)):
    return crud.get_post_by_reviewed(db, 1)


@app.post('/posts/review/{post_id}')
def review_post(post_id: int, choice: int = 0, db: Session = Depends(get_db)):
    print(choice)
    crud.review_post(db, post_id, choice)
    return JSONResponse({'message': '完成审阅'})


@app.get('/files/detail/{path}', response_class=HTMLResponse)
async def get_file(path: str):
    path = base64.b64decode(path)
    path = str(path, 'utf-8')
    with open(path, 'rb') as f:
        image = f.read()
    if os.path.splitext(path)[-1] == '.pdf':
        return Response(content=image, media_type='application/pdf')
    elif os.path.splitext(path)[-1] == '.doc':
        return Response(content=image, media_type='application/msword')
    elif os.path.splitext(path)[-1] == '.docx':
        return Response(content=image, media_type='application/vnd.openxmlformats-officedocument.wordprocessingml'
                                                  '.document')
    else:
        return Response(content=image, media_type='image/png')


@app.post('/banners')
async def create_banner(banner: schema.Banner, db: Session = Depends(get_db)):
    return crud.add_banner(db, banner)


@app.get('/banners')
async def get_banners(db: Session = Depends(get_db)):
    return crud.get_banners(db)


@app.get('/verification')
async def get_code(mail: str):
    try:
        verification = send_code(mail)
        return verification
    except Exception as e:
        raise HTTPException(status_code=401, detail=e.__traceback__)


@app.get('/logs')
def get_log():
    return logs
